package orchestration.android.execution;

import orchestration.android.execution.exceptions.LockException;
import orchestration.businessprocess.execution.BPExecution;
import orchestration.businessprocess.execution.IBPExecutionListener;
import orchestration.businessprocess.execution.Property;
import orchestration.businessprocess.model.nodes.BPNode;
import orchestration.utils.LockingUtils;
/**
 * this class incapsulates a BPExecution and permits to put a lock on it,
 * so that, once the BPExecution is associated to an Activity, only that
 * activity can call its resume() method (recursion over the same
 * BPExecution is not allowed).
 * @author  <a href="mailto:car.ferrarini@gmail.com">Carlo Ferrarini</a>
 */
public class AndroidLockableExecution{

	/**
	 * @uml.property  name="encryptedKey"
	 */
	private String encryptedKey;
	
	/**
	 * @uml.property  name="execution"
	 * @uml.associationEnd  
	 */
	private BPExecution execution;
	
	public AndroidLockableExecution(BPExecution execution,String encryptedKey) {
		this.execution=execution;
		this.encryptedKey=encryptedKey;
	}

	/**
	 * @return
	 * @uml.property  name="encryptedKey"
	 */
	public String getEncryptedKey() {
		return encryptedKey;
	}

	/**
	 * @param encryptedKey
	 * @uml.property  name="encryptedKey"
	 */
	public void setEncryptedKey(String encryptedKey) {
		this.encryptedKey = encryptedKey;
	}
	/**
	 * @return
	 * @uml.property  name="execution"
	 */
	public BPExecution getExecution(){
		return this.execution;
	}
	/**
	 * @param execution
	 * @uml.property  name="execution"
	 */
	public void setExecution(BPExecution execution) {
		this.execution = execution;
	}

	public synchronized boolean isLocked(){
		return this.encryptedKey!=null && !this.encryptedKey.equals("");
	}
	public synchronized String lock() throws LockException{
		if(!isLocked()){
			String key= LockingUtils.generateKey();
			encryptedKey= LockingUtils.encrypt(key);
			return key;
		}else
			throw new LockException("Already locked");
	}
	public synchronized void unlock(String key) throws LockException{
		if(!isLocked() || checkLock(key))
			this.encryptedKey="";
		else
			throw new LockException("Invalid encryptedKey");
	}
	
	public synchronized void resume(String key,boolean repeatLast) throws LockException{
		if(checkLock(key))
			execution.resume(repeatLast);
		else
			throw new LockException("Invalid encryptedKey");
	}

	private boolean checkLock(String key) throws LockException {
		return encryptedKey.equals(LockingUtils.encrypt(key));
	}
	
	public synchronized void saveProperty(String key,Property property) throws LockException{
		if(checkLock(key))
			execution.saveProperty(property);
		else
			throw new LockException("Invalid encryptedKey");
	}
	
	public synchronized void setListener(String key,IBPExecutionListener listener) throws LockException {
		String matchEncrypted = LockingUtils.encrypt(key);
		if(encryptedKey.equals(matchEncrypted))
			execution.setListener(listener);
		else
			throw new LockException("Invalid encryptedKey");
	}

	public BPNode getCurrentNode(String key) throws LockException {
		String matchEncrypted = LockingUtils.encrypt(key);
		if(encryptedKey.equals(matchEncrypted))
			return execution.getCurrentNode();
		else
			throw new LockException("Invalid encryptedKey");
	}
}